#pragma once

/**
@param	for both left and right: x,y,z = direction, w = normalized force, must be between 0 - 1
@remark  for keyboard, only left(mouse) is used. for controller, left = left analog, right = right analog. for wii & ps move & kinect, only left is used
*/
struct MoveParam
{
	vec4f left;
	vec4f right;

	MoveParam& operator+=(const MoveParam& rhs)
	{
		left += rhs.left;
		right += rhs.right;

		return (*this);
	}
};

class InputDevice
{
	friend class Input;
public:
	InputDevice(void) {}
	virtual ~InputDevice(void) {}

	virtual void update(float dt) = 0;
	virtual bool isKeyDown(int key) const = 0;
	virtual bool didKeyJustGoDown(int key) const = 0;
	virtual bool didKeyJustGoUp(int key) const = 0;
	virtual void getMove(MoveParam& mp) const = 0;
	virtual void registerKeys() = 0;

protected:
	// action related
	bool isActionDown(int actionId) const
	{
		int key = getKeyFromAction(actionId);
		if (key == -1)
		{
			return false;
		}

		// get key from action
		return isKeyDown(key);
	}
	bool didActionJustGoDown(int actionId) const
	{
		int key = getKeyFromAction(actionId);
		if (key == -1)
		{
			return false;
		}

		// get key from action
		return didKeyJustGoDown(key);
	}
	bool didActionJustGoUp(int actionId) const
	{
		int key = getKeyFromAction(actionId);
		if (key == -1)
		{
			return false;
		}

		// get key from action
		return didKeyJustGoUp(key);
	}
	void registerAction(int actionId, const std::string& keyName)
	{
		int key = -1;
		// get key from keyName
		std::map<std::string, int>::iterator keyIter = mapKeys.find(keyName);
		if (keyIter != mapKeys.end())
		{
			key = keyIter->second;
		}

		// overwrite if exists
		if (key != -1)
		{
			actions[actionId] = key;
		}
	}
	int getKeyFromAction(int actionId) const 
	{
		// get key from action
		std::map<int, int>::const_iterator actionIter = actions.find(actionId);
		if (actionIter != actions.end())
		{
			return actionIter->second;
		}

		return -1;
	}
	std::map<std::string, int> mapKeys;
	std::map<int, int> actions;
};

InputDevice* createKeyboardAndMouseInput();